package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.po.QueryCourseModel;
import com.xuecheng.api.content.model.vo.CourseBaseVO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.StatusEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.entity.CoursePub;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.feign.Client.SystemFeignClient;
import feign.template.QueryTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.nio.ContentEncoder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.beans.Transient;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {
    @Autowired
    private CourseBaseMapper courseBaseMapper;

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CourseTeacherService courseTeacherService;

    @Autowired
    private SystemFeignClient systemFeignClient;







    //查
    @Override
    public PageVO<CourseBaseDTO> queryCourseList(PageRequestParams params, QueryCourseModel model, Long companyId) {
        /**
         *   0. 是否开启事务
         *   1. 关键数据是否存在
         *   2. 业务数据是否完整
         *   3. 分页+条件查询 得到结果
         *   4. 封装对象返回结果
         */

//        0. 是否开启事务  否 增删改需要注解
//        1. 关键数据是否存在   若前端是人为传参，传递不存在的页面，导致系统崩溃，因此在这里限制当前页数
         if (params.getPageNo()<1){
             params.setPageNo(1L);
         }
         if(params.getPageSize()<1){
             params.setPageSize(20);
         }
         //构建 多条件查询对象
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

//        2. 业务数据是否完整 + 设置 多条件查询参数
        //判断请求提中的courseName是否存在
        if(StringUtil.isNotBlank(model.getCourseName())){
            queryWrapper.like(CourseBase::getName,model.getCourseName());
        }
        //判断请求体中的auditStatus 的状态是否存在，若存在直接按照状态查询
        if(StringUtil.isNotBlank(model.getAuditStatus())){
            queryWrapper.eq(CourseBase::getAuditStatus,model.getAuditStatus());
        }
        //只能查询自己家机构的课程信息，
        if(!(ObjectUtils.isEmpty(companyId))){
            queryWrapper.eq(CourseBase::getCompanyId,companyId);
        }


        //根据时间排序
        queryWrapper.eq(CourseBase::getStatus,1);
        queryWrapper.orderByDesc(CourseBase::getCreateDate);


//        3. 分页+条件查询 得到结果
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        Page<CourseBase> basePage = this.page(page, queryWrapper);

        long total = page.getTotal();
        List<CourseBase> records = page.getRecords();

        //前端只能接受DTO数据
        List<CourseBaseDTO> dtos=Collections.EMPTY_LIST;
        if(!(CollectionUtils.isEmpty(records))){
            //利用 Convert转换器 将从集合里取到的 vo对象再转化为 dto对象
            dtos = CourseBaseConvert.INSTANCE.entities2dtos(records);
        }



//        4. 封装对象返回结果
        PageVO<CourseBaseDTO> resultVo = new PageVO<>(dtos, total, params.getPageNo(), params.getPageSize());
        return resultVo;
    }

    // 增
    @Override
    @Transient
    public CourseBaseDTO createCourse(CourseBaseDTO dto) {

        /**  分析
         *   0. 是否开启事务支持 是
         *   1. 判断关键数据
         *   2. 判断业务数据
         *   3。 将对象转换为vo对象进行复制
         *   4. 将vo对象转换为dto
         *   5. 对结果进行封装
         *
         */

//        1. 判断关键数据
        verifyCourseMsg(dto);


//        2. 判断业务数据
        // 状态
        dto.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        // 因为数据库是vo对象，所以要转换vo对象放入数据库
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2vo(dto);
        // id 为mp自动补充  // id 要靠mp自动给生成，因为要和课程信息关联
        courseBase.setId(null);
        // 保存到数据库中
        boolean flag = this.save(courseBase);
        if(!flag){
            ExceptionCast.cast(ContentErrorCode.E_120001);
        }
        //mp 回调id
        Long courseBaseId = courseBase.getId();
        // 营销表要和 课程信息关联
        CourseMarket courseMarket = new CourseMarket();

        courseMarket.setCourseId(courseBaseId);
        float price = Float.parseFloat(dto.getPrice().toString());

        courseMarket.setPrice(price);
        courseMarket.setCharge(dto.getCharge());
        courseMarket.setId(null);

        boolean marketFlag = courseMarketService.save(courseMarket);
        if(!marketFlag){
            throw new RuntimeException("课程营销数据保存失败");
        }
//        3. 根据id获取数据，对象转换为vo对象
        CourseBase po = this.getById(courseBaseId);

//        4. 将vo对象转换为dto
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
//        5. 对结果进行封装
        return resultDTO;
    }
    // 改
    @Override
    public CourseBaseDTO modifyCourse(CourseBaseDTO dto, Long companyId) {
        /**
         *   0. 是否开启事务  是
         *   1.  判断关键数据   前端 数据库 接口

         *
         *   2.  判断业务数据  aompanyid  audit_status
         *            是否存在 要操作这个数据
         *            是否是同一家机构
         *            是否删除
         *            审核状态
         *
         *            课程营销类型
         *
         *   3， 进行业务操作（按照id将course对象查询出来，然后根据前端请求体对course对象覆盖，将对象保存进数据库）

         *   4.  查询数据库，封装成对象并返回给前端

         */

        //1.判断关键数据
        //  可以直接调用添加时对关键数据的判断
        //  判断课程的id不能为空

        //        1. 判断关键数据
        if(ObjectUtils.isEmpty(dto.getCompanyId())){
            throw new RuntimeException("公司id不能为空");
        }
        verifyCourseMsg(dto);

        Long courseBaseId = dto.getCourseBaseId();
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("修改课程id不能为空");
        }

        // 2.判断业务数据
        //   课程基础信息
        //     判断是否存在
        //     判断是否是同一家教学机构
        //     判断是否删除
        //     判断课程审核状态
        //        未提交和审核未通过才可以进行修改
        //   课程营销（根据courseid）
        getCourseByLogic(courseBaseId,dto.getCompanyId());

        //     课程营销
        CourseMarket courseMarket = getCourseMarketByCourseId(courseBaseId);


        // 将dto转为po
        //     课程基础信息表
        //         有些内容是不容修改的：companyid、auditstatus、status

        CourseBase po = CourseBaseConvert.INSTANCE.dto2vo(dto);
        po.setId(dto.getCourseBaseId());

        // 3.修改数据
        //   修改课程基础信息数据
        //   修改课程营销数据
        //   如果是收费课程，直接覆盖源数据（charge、price）
        po.setCompanyId(null);
        po.setAuditStatus(null);
        po.setStatus(null);

        boolean baseResult = this.updateById(po);

        if (!baseResult) {
            throw new RuntimeException("课程信息修改失败");
        }

        //     课程营销数据表
        //         charge price
        // 如果使用mq修改一张表中的极个别数据，UpdateWrapper
        // update course_market set charge=xxx,price=xxx  where courseid=xx
        LambdaUpdateWrapper<CourseMarket> marketUpdateWrapper = new LambdaUpdateWrapper<>();
        marketUpdateWrapper.set(CourseMarket::getCharge,dto.getCharge());

        String charge = dto.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {

            BigDecimal price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                throw new RuntimeException("收费课程价格不能为空");
            }

            marketUpdateWrapper.set(CourseMarket::getPrice, dto.getPrice().floatValue());
        } else {
            // 如果课程为免费，需要价格赋值为0
            marketUpdateWrapper.set(CourseMarket::getPrice, 0F);
        }
        marketUpdateWrapper.eq(CourseMarket::getCourseId, courseBaseId);


        boolean marketResult = courseMarketService.update(marketUpdateWrapper);

        //      修改数据时要判断修改后结果
        if (!marketResult) {
            throw new RuntimeException("修改课程营销数据失败");
        }


        // 4.将修改后的最新数据返回给前端
        CourseBaseDTO resultDTO = getLastCourseBaseDTO(dto, courseBaseId);

        return resultDTO;
    }
    //删
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {
        //删
    /*
        * 业务分析：
            1.是否要开启事务
                需要开启
            2.判断关键数据
                courseBaseId
                companyid
            3.判断业务数据
                判断课程是否存在
                判断是否是同一家机构
                判断课程是否已经删除
                判断课程的审核状态
                    未提交
                    审核未通过
                    只有这些状态才可以被删除
            4.删除课程基础信息（根据id删除）
                修改数据库的数据status
    * */

        // 2.判断关键数据
        //      courseBaseId
        //      companyid
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //3.判断业务数据
        //     判断课程是否存在
        //     判断是否是同一家机构
        //     判断课程是否已经删除
        //     判断课程的审核状态
        //         未提交
        //         审核未通过
        //         只有这些状态才可以被删除
        getCourseByLogic( courseBaseId,companyId);


        // 4.删除课程基础信息（根据id删除）
        //     修改数据库的数据status
        // update course_base set status = ? where course_id = ?
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getStatus,CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());

        updateWrapper.eq(CourseBase::getId, courseBaseId);

        boolean result = update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }


    }

    @Override
    @Transient
    public void commitCourseBase(Long courseBaseId, Long companyId) {
        /**
         *  0. 业务分析
         *  1. 判断关键数据
         *  2. 判断业务数据
         *  3. 改状态
         *
         */
        // 1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        // 2.判断业务数据
        //    课程基础信息
        //       判断是否存在
        //       判断是否是同一家机构
        //       判断是否删除
        //       判断审核状态：未提交、审核未通过
        getCourseByLogic(courseBaseId,companyId);
         //  3. 修改课程 已提交
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus,CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate,LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId,courseBaseId);

        boolean result = this.update(updateWrapper);

        if(!result){
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }



    }


    private void verifyCourseMsg(CourseBaseDTO dto) {


        if(ObjectUtils.isEmpty(dto.getGrade())){
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }

        if (StringUtil.isBlank(dto.getName())) {
            throw new RuntimeException("课程名称不能为空");
        }

        if (StringUtil.isBlank(dto.getMt())) {
            throw new RuntimeException("课程大分类不能为空");
        }

        if (StringUtil.isBlank(dto.getSt())) {
            throw new RuntimeException("课程小分类不能为空");
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            throw new RuntimeException("课程教学模式不能为空");
        }

//        if (StringUtil.isBlank(dto.getUsers())) {
//            throw new RuntimeException("使用人群不能为空");
//        }

        String charge = dto.getCharge();
        if (StringUtil.isBlank(charge)) {
            throw new RuntimeException("课程收费不能为空");
        }
        //如果是收费可课程要写价格
        //如果是收费课程
        if(charge.equals(CourseChargeEnum.CHARGE_YES.getDesc())){
            //价格不能为空
            if(ObjectUtils.isEmpty(dto.getPrice())){
                throw  new RuntimeException("课程价格不能为空！");
            }
        }else{  //如果不收费，就让价格为0元
            dto.setPrice(new BigDecimal("0"));
        }
    }

    @Override
    public CourseBaseDTO getCourseById(Long courseBaseId, Long companyId) {

        /**
         *  1.判断关键数据：前端传来的数据，需要校验的内容
         *  2.判断业务数据：根据关键数据来操作的数据内容，在后端存储
         *    判断课程信息是否存在
         *    根据id来查询
         *    判断是否是同一家机构 ->将数据库中的CourseBase里Companyid和前端传来的Companyid进行对比
         *
         * @param courseBaseId
         * @param companyId
         * @return
         */

        // 1.判断关键数据：前端传来的数据，需要校验的内容
        //   courseBaseId,  companyId

        if (ObjectUtils.isEmpty(courseBaseId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            throw new RuntimeException("传入参数和接口不匹配");
        }

        // 2.判断业务数据：根据关键数据来操作的数据内容，在后端存储
        //   判断课程信息是否存在
        //    根据id来查询
        //   判断是否是同一家机构
        //      将数据库中的CourseBase里Companyid和前端传来的Companyid进行对比

        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        // 3.将po数据转为dto并返回
        //  courseBase
        //  courseMarket
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        //     课程营销
        CourseMarket courseMarket = getCourseMarketByCourseId(courseBaseId);

        courseBaseDTO.setCharge(courseMarket.getCharge());
        courseBaseDTO.setPrice(new BigDecimal(courseMarket.getPrice().toString()));

        return courseBaseDTO;
    }
    // 检查课程状态
    // 必须是未提交或者是未审核通过才能修改
    private void getCourseByLogic(Long courseBaseId, Long companyId) {

        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }
    }
    // 根据id查询数据库对象 返回给前端
    private CourseBaseDTO getLastCourseBaseDTO(CourseBaseDTO dto, Long id) {
        CourseBase po = this.getById(id);

        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
        return resultDTO;
    }

    private CourseMarket getCourseMarketByCourseId(Long courseBaseId) {
        LambdaQueryWrapper<CourseMarket> marketQueryWrapper = new LambdaQueryWrapper<>();
        marketQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        CourseMarket courseMarket = courseMarketService.getOne(marketQueryWrapper);

        if (ObjectUtils.isEmpty(courseMarket)) {
            throw new RuntimeException("课程营销数据不存在");
        }
        return courseMarket;
    }

    private CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        // select * from course_base where id = ? and companyId = ?
        LambdaQueryWrapper<CourseBase> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(CourseBase::getId, courseBaseId);
        baseQueryWrapper.eq(CourseBase::getCompanyId, companyId);
        // baseQueryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());

        CourseBase courseBase = this.getOne(baseQueryWrapper);

        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程不存在");
        }

        Integer status = courseBase.getStatus();
        if (!(CommonEnum.USING_FLAG.getCodeInt().equals(status))) {
            throw new RuntimeException("课程信息已经被删除");
        }
        return courseBase;
    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       auditMind  auditStatus  courseid
     *
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否删除
     *           判断审核状态
     *               必须为：已提交
     *       审核状态
     *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
     *   3.修改课程审核信息
     *       auditMind  auditStatus  auditNum（每次+1）
     * */

    // TODO : 审核没做
    @Transactional
    public void approveCourse(CourseBaseDTO dto) {

        // 1.判断关键数据
        //      auditMind  auditStatus  courseid
        if (StringUtil.isBlank(dto.getAuditMind())||
                StringUtil.isBlank(dto.getAuditStatus())||
                ObjectUtils.isEmpty(dto.getCourseBaseId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        //  2.判断业务数据
        //      课程基础信息
        //          判断是否存在
        //          判断是否删除
        //          判断审核状态
        //              必须为：已提交
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());
        queryWrapper.eq(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());

        int count = this.count(queryWrapper);

        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }


        //      审核状态
        //          运营平台只能给课程审核状态赋值：审核通过、审核未通过
        String auditStatus = dto.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120016);
        }



        //  3.修改课程审核信息
        //      auditMind  auditStatus  auditNum（每次+1）
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, dto.getAuditStatus());
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());

        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId());

        boolean result = this.update(updateWrapper);

        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

    }




}
